import Renderer from "../../../lib/renderer/Renderer.js"
import lodash from "lodash"
import { chromium } from "playwright"
import cfg from "../../../lib/config/config.js"
import os from "os"
import fs from "fs"

const _path = process.cwd()

/**
 * 获取默认的Chromium/Chrome/Edge浏览器可执行文件路径
 * 根据不同操作系统查找常见的浏览器安装路径
 */
function getDefaultChromiumPath() {
  const platform = os.platform()
  if (platform === "win32") {
    const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
    const chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
    return [edgePath, chromePath].find(p => fs.existsSync(p))
  }
  if (platform === "darwin") {
    const chromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
    const edgePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
    return [chromePath, edgePath].find(p => fs.existsSync(p))
  }
  if (platform === "linux") {
    const chromiumBrowserPath = "/usr/bin/chromium-browser"
    const chromiumPath = "/usr/bin/chromium"
    const chromePath = "/usr/bin/google-chrome"
    const edgePath = "/usr/bin/microsoft-edge"
    return [chromiumBrowserPath, chromiumPath, chromePath, edgePath].find(p => fs.existsSync(p))
  }
  logger.warn("未检测到可用的Chromium/Chrome/Edge浏览器路径 请手动配置浏览器安装路径")
  return undefined
}

/**
 * Playwright 渲染器类，继承自Renderer
 * 用于通过Playwright生成网页截图
 */
export default class Playwright extends Renderer {
  static _browserInstance = null
  static _processEventsRegistered = false

  constructor(config) {
    super({
      id: "playwright",
      type: "image",
      render: "screenshot"
    })
    // 浏览器实例
    this.browser = false
    // 启动锁，防止并发初始化
    this.lock = false
    // 当前正在截图的任务名队列
    this.shooting = []
    // 达到restartNum次渲染后自动重启浏览器
    this.restartNum = 100
    // 已渲染次数计数
    this.renderNum = 0
    // 渲染配置
    this.config = {
      headless: config.headless !== undefined ? config.headless : true,
      args: config.args || [
        "--disable-gpu",
        "--disable-setuid-sandbox",
        "--no-sandbox",
        "--no-zygote",
        "--font-render-hinting=full"
      ],
      executablePath: config.chromiumPath || cfg?.bot?.chromium_path || getDefaultChromiumPath()
    }
    this.playwrightTimeout = config.playwrightTimeout || 0
    this.pageGotoParams = config.pageGotoParams || {
      timeout: 120000,
      waitUntil: "networkidle"
    }

    // 进程退出时关闭浏览器
    if (!Playwright._processEventsRegistered) {
      process.on('exit', () => {
        if (Playwright._browserInstance?.close) Playwright._browserInstance.close()
      })
      process.on('SIGINT', async () => {
        try { if (Playwright._browserInstance?.close) await Playwright._browserInstance.close() } catch {}
        process.exit()
      })
      process.on('SIGTERM', async () => {
        try { if (Playwright._browserInstance?.close) await Playwright._browserInstance.close() } catch {}
        process.exit()
      })
      Playwright._processEventsRegistered = true
    }
  }

  /**
   * 初始化浏览器实例（单例）
   * 防止并发重复启动
   */
  async browserInit() {
    if (this.browser) return this.browser
    if (this.lock) return false
    this.lock = true

    logger.info("playwright Chromium 启动中...")

    try {
      this.browser = await chromium.launch(this.config)
      Playwright._browserInstance = this.browser
    } catch (err) {
      logger.error("playwright Chromium 启动失败", err)
      this.lock = false
      return false
    }

    this.lock = false
    logger.info("playwright Chromium 启动成功")
    /** 监听Chromium实例是否断开 */
    this.browser.on("disconnected", async () => await this.restart(true))

    return this.browser
  }

  /**
   * 截图主方法
   * @param {string} name 模板名
   * @param {object} data 渲染参数，可选字段：
   *   - imgType           图片类型（如 "jpeg"）
   *   - quality           jpeg 质量
   *   - fullPage          是否全页截图
   *   - omitBackground    是否忽略背景
   *   - screenshotTimeout 截图超时时间
   *   - pageGotoParams    页面跳转参数（timeout, waitUntil），可覆盖全局设置
   * @returns {Buffer|false} 图片 Buffer 或 false
   */
  async screenshot(name, data = {}) {
    if (!await this.browserInit()) return false

    const savePath = this.dealTpl(name, data)
    const start = Date.now()
    if (!savePath) return false

    let buff = ""
    let context = null
    let page = null
    this.shooting.push(name)
    try {
      context = await this.browser.newContext()
      page = await context.newPage()
      // 校验waitUntil参数
      const validWaitUntil = ['load', 'domcontentloaded', 'networkidle', 'commit']
      let waitUntil = data.pageGotoParams?.waitUntil || this.pageGotoParams.waitUntil
      if (!validWaitUntil.includes(waitUntil)) waitUntil = 'load'

      const pageGotoParams = {
        timeout: (data.pageGotoParams?.timeout || this.pageGotoParams.timeout),
        waitUntil
      }
      await page.goto(`file://${_path}${lodash.trim(savePath, ".")}`, pageGotoParams)

    // Linux的用户可以放出来，渲染出的字体看起来更接近win，更舒服些
    // win用户别管，避免字体过粗
    //  await page.addStyleTag({
    //    content: `* { -webkit-text-stroke: 0.3px !important; }`
    // })

      const jpegQuality = data.imgType === "jpeg"
        ? (data.quality !== undefined ? data.quality : 90)
        : undefined

      if (data.fullPage) {
        buff = await page.screenshot({
          type: data.imgType || "jpeg",
          quality: jpegQuality,
          omitBackground: data.omitBackground || false,
          fullPage: true,
          timeout: data.screenshotTimeout || this.playwrightTimeout || 0
        })
      } else {
        const body = await page.$("#container") || await page.$("body")
        if (!body) {
          logger.error(`[图片生成][${name}] 页面无可截图元素`)
          return false
        }
        buff = await body.screenshot({
          type: data.imgType || "jpeg",
          quality: jpegQuality,
          omitBackground: data.omitBackground || false,
          timeout: data.screenshotTimeout || this.playwrightTimeout || 0
        })
      }

      this.renderNum++
      const kb = (buff.length / 1024).toFixed(2) + "KB"
      logger.mark(`[图片生成][${name}][${this.renderNum}次] ${kb} ${logger.green(`${Date.now() - start}ms`)}`)
    } catch (err) {
      logger.error(`[图片生成][${name}] 图片生成失败`, err)
      await this.restart(true)
      return false
    } finally {
      if (page) await page.close().catch(() => {})
      if (context) await context.close().catch(() => {})
      this.shooting = this.shooting.filter(n => n !== name)
    }

    if (!buff) {
      logger.error(`[图片生成][${name}] 图片生成为空`)
      return false
    }

    await this.restart()
    return buff
  }

  /**
   * 浏览器重启逻辑
   * @param {boolean} force 是否强制重启
   */
  async restart(force = false) {
    if (!this.browser?.close || this.lock) return
    if (!force) {
      if (this.renderNum % this.restartNum !== 0 || this.shooting.length > 0) return
    }
    logger.info(`playwright Chromium ${force ? "强制" : ""}关闭重启...`)
    await this.stop(this.browser)
    this.browser = false
    return this.browserInit()
  }

  /**
   * 停止并关闭浏览器实例
   * @param {object} browser 浏览器实例
   */
  async stop(browser) {
    try {
      await browser.close()
    } catch (err) {
      logger.error("playwright Chromium 关闭错误", err)
    }
  }
}